var cotripDocBase = "http://cotrip.org/",
	//cotripDocBase = "http://localhost:8085/",
	xmlDocBase 	  = cotripDocBase+"xml/",
	useNameSpace  = true,	//Use name space while reading elements.	
	Renderers = {
		/**
		 * Location renderer
		 * 
		 * @param $location
		 */	
		locationRenderer: function($location) {
			return findElement($location, 'Latitude', 'global').text()+", "+findElement($location, 'Longitude', 'global').text()
		}, 
		
		/**
		 * Icon Renderer
		 * 
		 * @param $icon
		 */
		iconRenderer	: function($icon) {
			return '<img src="'+cotripDocBase+$icon.text()+'"/>';
		},
		
		travelTimeRenderer: function($travelTime) {
			var hoursEl 	= findElement($travelTime, 'Hours', 'speed'),
				minutesEl	= findElement($travelTime, 'Minutes', 'speed'),
				retVal		= '';
			if(hoursEl && hoursEl.text()) {
				retVal += hoursEl.text()+' Hours';
			}
			
			if(minutesEl) {
				retVal += minutesEl.text()+' Minutes';
			}
			return retVal;
		}
	},
	
	/**
	 * XML Reader configuration.
	 */
	xmlRef 		  = {
		//Alerts.	
		Alerts	: {
			url			: 'alerts.xml',
			namespace	: 'alert',
			nodes		: 'Alert',
			fields		: [{
				name:  'AlertId'
			}, {
				name	:  'Type'
			}, {
				name	:  'Headline'
			}, {
				name	:  'Description'
			}, {
				name	:  'Impact'
			}, {
				name	:  'Location',
				renderer: Renderers.locationRenderer
			}, {
				name	: 'ReportedTime'
			}, {
				name 	: 'LastUpdatedDate'
			}, {
				name	: 'AlertIcon',
				renderer: Renderers.iconRenderer
			}, {
				name	: 'Direction' 
			}, {
				name	: 'IsBothDirectionFlg' 
			}, {
				name	: 'RoadName'
			}, {
				name	: 'StartMileMarker'
			}, {
				name	: 'EndMileMarker'
			}]
		},
		
		Announcement	: {
			url			: 'announcement.xml',
			nodes		: 'Announcement',
			namespace	: 'announcement',
			fields		: [{
				name:  'AnnouncementId'
			}, {
				name	:  'TypeAnnouncementTxt'
			}, {
				name	:  'TypeAnnouncementSeverityTxt'
			}, {
				name	:  'AnnouncementDescription'
			}, {
				name	:  'StartTime'
			}, {
				name	:  'LastUpdateDate'
			}, 
//			{
//				name	: 'TypeForegroundColorRGB'
//			}, {
//				name 	: 'TypeBackgroundColorRGB'
//			}, {
//				name	: 'MessageForegroundColorRGB',
//			}, {
//				name	: 'MessageBackgroundColorRGB' 
//			}, 
			
			{
				name	: 'AnnouncementIcon',
				renderer: Renderers.iconRenderer				
			}]
		},
		
		'Road Conditions'	: {
			url			: 'road_conditions.xml',
			nodes		: 'WeatherRoute',
			namespace	: 'rc',
			fields		: [{
				name	:  'WeatherRouteId'
			}, {
				name	:  'RouteName'
			}, {
				name	:  'Status'
			}, {
				name	:  'StartMileMarker'
			}, {
				name	:  'EndMileMarker'
			}, {
				name	:  'Length'
			}, {
				name	:  'CalculatedDate'
			}, {
				name	:  'RoadName'
			}, {
				name	:  'RoadConditionCategoryTxt'
			}, {
				name	:  'RouteGroupTxt'
			}, {
				name	:  'IsHazardousCondition'
			}]
		},
		
		'Speed Routes'	: {
			url			: 'speed_routes.xml',
			nodes		: 'Route',
			namespace	: 'speed',
			fields		: [{
				name	:  'RouteId'
			}, {
				name	:  'RouteName'
			}, {
				name	:  'Description'
			}, {
				name	:  'Status'
			}, {
				name	:  'ExpectedTravelTime',
				renderer:  Renderers.travelTimeRenderer
			}, {
				name	:  'CalculatedDate'
			}, {
				name	:  'AverageSpeed'
			}, {
				name	:  'RoadInfo',
				renderer:  function($roadInfo) {
					var roadNameEl 	= findElement($roadInfo, 'RoadName', 'speed'),
						directionsEl= findElement($roadInfo, 'DirectionTxt', 'speed'),
						retVal		= '';
					
					if(roadNameEl) {
						retVal += roadNameEl.text()+' ';
					}
					
					if(directionsEl) {
						retVal += directionsEl.text();
					}
					return retVal;
				}
			}, {
				name	:  'Length'
			}]
		}, 
		
		'Speed Segments' : {
			url			: 'speed_segments.xml',
			nodes		: 'Segment',
			namespace	: 'speed',
			fields		: [{
				name	:  'SegmentId'
			}, {
				name	:  'SegmentName'
			}, {
				name	:  'SegmentType'
			}, {
				name	:  'RoadName'
			}, {
				name	:  'Direction'
			}, {
				name	:  'SpeedLimit'
			}, {
				name	:  'Length'
			}, {
				name	:  'StartMileMarker'
			}, {
				name	:  'EndMileMarker'
			}, {
				name	:  'Status'
			}, {
				name	:  'Status'
			}, {
				name	:  'ExpectedTravelTime',
				renderer: Renderers.travelTimeRenderer
			}, {
				name	:  'CalculatedDate'
			}]
		}, 
		
		'DMS'	: 	{
			url			: 'dms.xml',
			nodes		: 'DMS',
			namespace	: 'dms',
			fields		: [{
				name	:  'DMSId',
				label	:  'DMS Id'
			}, {
				name	:  'BlankMessage'
			}, {
				name	:  'Message'
			}, {
				name	:  'MessageImage',
				renderer:  Renderers.iconRenderer
			}, {
				name	:  'Location',
				renderer:  Renderers.locationRenderer	
			}, {
				name	:  'Device>global:DeviceId'
			}, {
				name	:  'Device>global:CommonName'
			}, {
				name	:  'Device>global:Status'
			}, {
				name	:  'Device>global:EntityId'
			}, {
				name	:  'Device>global:RoadId'
			}, {
				name	:  'Device>global:RoadName'
			}, {
				name	:  'Device>global:Direction'
			}, {
				name	:  'Device>global:MileMarker'
			}, {
				name	:  'Device>global:LastUpdateDate'
			}, {
				name	:  'Device>global:Icon',
				renderer:  Renderers.iconRenderer
			}]
		}, 
		
		'Streaming Cameras'	: 	{
			url			: 'streaming_cameras.xml',
			nodes		: 'Camera',
			namespace	: 'camera',
			fields		: [{
				name	:  'CameraId'
			}, {
				name	:  'CameraType'
			}, {
				name	:  'Name'
			}, {
				name	:  'Description'
			}, {
				name	:  'Status'
			}, {
				name	:  'IsWeatherStation'
			}, {
				name	:  'Source'
			}, {
				name	:  'Icon',
				renderer:  Renderers.iconRenderer
			}, {
				name	:  'Location',
				renderer:  Renderers.locationRenderer	
			}]
		},
		
		'Weather Stations': {
			url			: 'weatherstation.xml',
			nodes		: 'WeatherStation',
			namespace	: 'ws',
			fields		: [{
				name	:  'WeatherStationId',
				label	: 'WS Id'
			}, {
				name	:  'ConfigurationId'
			}, {
				name	:  'Manufacturer'
			}, {
				name	:  'Location',
				renderer:  Renderers.locationRenderer	
			}, {
				name	:  'Device>global:DeviceId'
			}, {
				name	:  'Device>global:CommonName'
			}, {
				name	:  'Device>global:Status'
			}, {
				name	:  'Device>global:EntityId'
			}, {
				name	:  'Device>global:RoadId'
			}, {
				name	:  'Device>global:RoadName'
			}, {
				name	:  'Device>global:Direction'
			}, {
				name	:  'Device>global:MileMarker'
			}, {
				name	:  'Device>global:LastUpdateDate'
			}, {
				name	:  'Device>global:Icon',
				renderer:  Renderers.iconRenderer
			}]
		}
	};

/**
 * Initializes the page.
 */
$(document).ready(function() {
	var xmlOptions 		= '',
		$xmlList		= $('#xmlList'),
		$xmlSelectBtn	= $('#xmlSelectBtn');
	
	useNameSpace 	= !($.browser.webkit == true);
	
	$.each(xmlRef, function(pKey, pValue) {
		xmlOptions += '<option value="'+pKey+'">'+pKey+'</option>';
	});
	
	$xmlList.append(xmlOptions);
	$xmlSelectBtn.bind('click', function() {
		populateXML($xmlList.val());
	});
 });

/**
 * Populates the Given XML in the contents table.
 * 
 * @param pXMLName
 */
function populateXML(pXMLName) {
	var $xmlContentsDiv = $("#xmlContents"),
		xmlDetailsObj	= xmlRef[pXMLName],
		xmlURL			= xmlDocBase+ xmlDetailsObj['url'],
		nodeSelector	= xmlDetailsObj['nodes'],
		nameSpace		= xmlDetailsObj['namespace'],
		tableContents	= '<table border="1" cellspacing="0" cellpadding="5"><tr>', 
		xmlNode			= null,
		xmlElement		= null,
		dataType		= "jsonp"; //default
	
	$("input:radio[name=connectionType]").each(function(pIndex, pElement) {
		if(pElement.checked) {
			dataType = pElement.value;
		}
	});
	
	$xmlContentsDiv.html('Please wait. Loading Contents...')
		
	$.each(xmlDetailsObj.fields, function(pIndex, pElement) {
		tableContents += '<th>'+(pElement['label'] || createLabel(pElement['name'])).replace(">", " ")+'</th>';
	});
	
	tableContents	+= '</tr>';
		
	$.ajax({
		type		: "GET",
		url			: xmlURL,
		dataType	: dataType, //Use jsonp to directly go to the cotrip URL. use text otherwise
	
		/**	
		 * Handles the success.
		 * 
		 * @param xml - XML that is read.
		 */
		success: function(xmlStr) {
			if(typeof xmlStr == 'object') {
				xmlStr = xmlStr.responseText;
			}
			var xml = $.parseXML(xmlStr);
			
			findElement($(xml), nodeSelector, nameSpace).each(function() {
				
				tableContents += '<tr>';
				xmlNode = $(this);
				
				$.each(xmlDetailsObj.fields, function(pIndex, pElement) {
					tableContents += '<td>';
					//apply the contents.
					xmlElement = findElement(xmlNode, pElement['name'], nameSpace);
					if(pElement['renderer']) {
						tableContents += pElement['renderer'](xmlElement); 
					} else {
						tableContents += xmlElement.text();
					}
					
					tableContents += '</td>';
				});
				
				tableContents += '</tr>';
			});
			tableContents += '</table>';
			$xmlContentsDiv.html(tableContents);
		},
		
		/**
		 * Handles Failure.
		 */
		error: function() {
			tableContents += '<tr><td colspan="'+xmlDetailsObj.fields.length+'">Failed to fetch XML</td></tr></table>';
			$xmlContentsDiv.html(tableContents);
		}
	});
}	

/**
 * Finds an element by the given string
 * 
 * @param xmlNode 	- XML Node
 * @param pSelector - String Selector.
 */
function findElement(xmlNode, pSelector, pNameSpace) {
	var me 			= this,
		selectors 	= null,
		nameSpaceSplit = null;
	if(xmlNode) {
		if(pSelector.indexOf(">") != -1) {
			var selectors = pSelector.split(">");
			$.each(selectors, function(pIndex, selector) {
				xmlNode = me.findElement(xmlNode, fixElementNameWithNameSpace(selector), pNameSpace);
			});
			return xmlNode;
		} else {
			
			//add namespace if required.
			if(useNameSpace && pNameSpace && pSelector.indexOf(':') == -1) {
				pSelector = pNameSpace+"\\:"+pSelector;
			}

			return xmlNode.find($.trim(pSelector));
		}
	} else {
		return [];
	}
}

/**
 * Fixes the name space format to match the style expected by jQuery.
 * 
 * @param pElementName
 * @returns
 */
function fixElementNameWithNameSpace(pElementName) {
	var retVal 			= pElementName,
		nameSpaceSplit 	= null;
	if(pElementName.indexOf(':') != -1) {
		nameSpaceSplit =  pElementName.split(':');
		if(nameSpaceSplit.length > 1) {
			if(useNameSpace) {
				retVal = nameSpaceSplit[0]+"\\:"+nameSpaceSplit[1]; 
			} else {
				retVal = nameSpaceSplit[1];
			}
		}
	}
	
	return retVal;
}

/**
 * Creates a label out of the xml element name.
 * (Mainly converts the camel case style into separate words)
 * 
 * @param pXMLElementName
 * @returns
 */
function createLabel(pXMLElementName) {
	//Regex obtained from the forum - http://stackoverflow.com/questions/4149276/javascript-camelcase-to-regular-form
	var camelCaseCleared = $.trim(pXMLElementName.replace(/([A-Z])/g, ' $1').replace(/^./, function(str){ return str.toUpperCase(); })).split(' '),
		retValue 		 = '';
	$.each(camelCaseCleared, function(pIndex, pElement) {
		if(pIndex > 0) {
			retValue += ' ';
		}
		if(pElement.indexOf(':') != -1) {
			pElement = pElement.split(':')[1];
		}
		
		retValue += pElement;
	});
	return retValue;	
}